<?php
/**
 * @author ArthurH
 * Router class part of ArhFrame (My own php framework) remodified
 * modified by:
 * @author ArthurH, Bertrand
 *
 *
 */
function getRoute()
{
    $route = Router::getInstance();
    try {
        if (func_num_args() > 0) {
            return Router::writeRoute(call_user_func_array(array($route, "getRouteByName"), func_get_args()));
        } else {
            return $route->getCurrentRoute();
        }
    } catch (Exception $e) {
        throw new Exception($e->getMessage());
    }
}

Class Router
{
    private static $_instance = null;
    private $routeRequest;
    private $viewFolder;
    private $info = array();
    public $route = array();
    private $controllerPath = '';
    private $controller;
    private $nameroute;
    private $pattern;
    private $validation;
    private $type = 'Everything';
    private $static;

    private function __construct()
    {

        $this->routeRequest = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : '/';
        //$this->routeRequest = $_SERVER['PATH_INFO'];
        if (empty($this->routeRequest)) {
            $this->routeRequest = '/';
        }
        $this->viewFolder = ROOT . '/vue';
    }

    public function addRoute($routeName, array $arrayRoute)
    {
        $arrayRoute = array($routeName => $arrayRoute);
        $this->route = array_merge($this->route, $arrayRoute);
    }

    public static function getInstance()
    {
        if (is_null(self::$_instance)) {
            self::$_instance = new Router();
        }

        return self::$_instance;
    }

    public function loadRoute()
    {
        $maxPattern = 0;
        foreach ($this->route as $key => $value) {
            $value['controller'] = $this->controllerPath . '/' . $value['controller'];
            if (!is_file($value['controller'])) {
                throw new Exception("Controller file '" . $value['controller'] . "' doesn't exist for route '$key'");
            }
            $pattern = preg_replace("#(\\\{\w*\\\})#", '(.*)', preg_quote($value['pattern']));
            $methodCorrect = true;
            $typeCorrect = true;
            if ($this->pattern == $value['pattern'] && empty($value['method'])) {
                $methodCorrect = ("GET" == strtoupper($_SERVER['REQUEST_METHOD']));
            } elseif (!empty($value['method'])) {
                $methodCorrect = (strtoupper($value['method']) == strtoupper($_SERVER['REQUEST_METHOD']));
            }
            if ($this->pattern == $value['pattern'] && empty($value['type'])) {
                $typeCorrect = true;
            }
            if (preg_match('#^' . $pattern . '?#', $this->routeRequest) && strlen($pattern) >= $maxPattern && $methodCorrect && $typeCorrect) {
                $this->validation = $value['validation'];
                preg_match_all('#^' . $pattern . '?#', $this->routeRequest, $tabInfo);
                preg_match_all("#\{\w*\}#", $value['pattern'], $tabNameInfo);
                foreach ($tabNameInfo[0] as $element => $nameInfo) {
                    $nameInfo = substr($nameInfo, 1, strlen($nameInfo) - 2);
                    $this->info[$nameInfo] = $tabInfo[$element + 1][0];
                }
                if (!$this->validateInfo()) {
                    continue;
                }
                $maxPattern = strlen($pattern);
                $this->controller = $value['controller'];
                $this->nameroute = $key;
                $this->pattern = $value['pattern'];
                //$this->static = $value['static'];

            }
        }
    }

    private function validateInfo()
    {
        $validation = $this->validation;
        $infos = $this->info;
        if (empty($validation) || empty($infos) || !is_array($validation) || !is_array($infos)) {
            return true;
        }
        foreach ($infos as $name => $value) {
            if (empty($validation[$name])) {
                continue;
            }
            $preg = preg_match('#' . $validation[$name] . '#', $value);
            if (empty($preg)) {
                $this->info = null;
                $this->validation = null;
                return false;
            }
        }
        return true;

    }

    public function getController()
    {
        return $this->controller;
    }

    public function getInfo()
    {
        return $this->info;
    }

    public function getNameRoute()
    {
        return $this->nameroute;
    }

    public static function getCurrentRoute()
    {

        return HTTPNAME . '/index.php' . $_SERVER['PATH_INFO'];

    }

    public static function writeRoute($pattern)
    {

        return HTTPNAME . '/index.php' . $pattern;

    }

    public function getRouteByName($name)
    {
        $args = func_get_args();
        $route = $this->route;
        if (empty($route[$name])) {
            throw new Exception('The route "' . $name . '" doesn\'t exist.');

        }
        $pattern = $route[$name]['pattern'];
        preg_match_all("#\{\w*\}#", $pattern, $tabNameInfo);
        if (count($tabNameInfo[0]) > func_num_args() - 1) {
            $nbValue = count($tabNameInfo[0]) - func_num_args() + 1;
            throw new Exception("You need to follow the pattern \"" . $pattern . "\" miss " . $nbValue . " value.");
        }
        for ($i = 0; $i < count($tabNameInfo[0]); $i++) {
            $pattern = preg_replace("#\{\w*\}#", $args[$i + 1], $pattern, 1);
        }

        return $pattern;
    }

    public function __toString()
    {
        return "Route path: " . $this->getCurrentRoute()
        . "\nRoute name: " . $this->getNameRoute()
        . "\nRoute controller: " . $this->getController()
        . "\nRoute action: " . $this->getAction()
        . "\nRoute method: " . $this->getMethod()
        . "\nRoute is static: " . ($this->static ? 'true' : 'false');
    }

    public function getControllerPath()
    {
        return $this->controllerPath;
    }

    public function setControllerPath($controllerPath)
    {
        $this->controllerPath = $controllerPath;
        return $this;
    }

}
